home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 037a / mou_rout.zip / MOU.DOC < prev    next >
Text File  |  1991-01-08  |  21KB  |  422 lines

  1.             Turbo and Microsoft C Mouse Routines - Release 1.0
  2.             --------------------------------------------------
  3.  
  4. Tue Jan 8, 1991.
  5.  
  6. CONTENTS
  7.  
  8.   1. What do these routines do?
  9.   2. How it works.
  10.   3. Variable and definition reference.
  11.   4. Function reference.
  12.   5. The test program.
  13.   6. Disclaimer and other stuff.
  14.  
  15.  
  16. 1. What do these routines do?
  17. -----------------------------
  18.  
  19. These routines will allow you to interface with the mouse driver in your
  20. programs.  It works with Microsoft compatible mouse drivers (i.e. Logitech,
  21. PC Mouse, Dexxa, etc).  The routines have the added feature of displaying a
  22. 'true' mouse cursor in text mode on an EGA or VGA by reprograming the font
  23. on the fly.
  24.  
  25. The routines consist of several functions used to initialize, draw the
  26. cursor, and get mouse events (button presses).
  27.  
  28. These routines do not handle drawing the mouse cursor in graphics mode,
  29. only text mode.  If the routines detect the presense of an EGA/VGA adapter,
  30. it will use the 'true' mouse cursor, if not it will use a simple block
  31. cursor implemented by switch the foreground/background colors of the
  32. position the cursor is.
  33.  
  34. 2. How it works.
  35. ---------------
  36.  
  37. All character coordinates used by the mouse driver are zero based.  I.e. in
  38. 80x25 text mode the range of values for x and y are 0-79 and 0-24.  The
  39. routines should work in all memory models.
  40.  
  41. The routines first check for the presense of a mouse driver, and if none is
  42. present, they return without doing anything.  It is safe to call the
  43. routines such as MOUhide() and others even if a mouse is not installed,
  44. they will simply return.
  45.  
  46. Once the presense of a Microsoft compatible mouse driver is verified, the
  47. routine checks the presense of DESQview and an EGA/VGA.  If an EGA/VGA is
  48. in the system, and the program is not running under DESQview, the routines
  49. will choose to use a 'true' cursor, otherwise a simple block cursor will be
  50. used.  A 'true' cursor is not used under DESQview because DESQview doesn't
  51. really like having it's font changed on the fly by a program.  The 'true'
  52. mouse cursor would probably interfere with other programs running at the
  53. same time.
  54.  
  55. The mouse driver does have a glitch that these routines have to work
  56. around, that being that when in text mode, the mouse driver returns the
  57. coordinates as multiples of 8 (i.e. 0, 8, 16, 24 ...).  Since the 'true'
  58. cursor has a pixel resolution, we need to get the mouse driver to return
  59. coordinates in pixels (i.e. 0, 1, 2, 3 ...).  To do this, we 'trick' the
  60. mouse driver into thinking it is in graphics mode (where coordinates are
  61. returned in pixels) by changing the current video mode.  This is done by
  62. placing a value of 6 in memory location 0x0040:0x0049, 6 being the number
  63. for CGA 640x200 2 color graphics mode.  We then tell the mouse driver to
  64. initialize again (using mouse driver function 0), and the mouse driver
  65. checks the video mode, sees that we are in graphics mode, and sets itself
  66. up accordingly.  We then restore the mode byte at 0x0040:0x0049 to it's
  67. previous value.  After this, the mouse driver returns all coordinates in
  68. pixels.  I had to hack out this fix on my own, I called Microsoft and got
  69. nothing from them, but I remembered that when you are running the mouse
  70. driver in graphics mode on a Hercules graphics adapter, you have to do this
  71. 'trick.'  It worked in this case as well.
  72.  
  73. Next the initialization routine sets up the maximum x and y ranges for the
  74. mouse cursor based on the dimensions of the video mode.  Lastly it installs a
  75. mouse function handler using mouse driver function 12 -- define handler.
  76. The handler is installed for mouse movement, and left or right button
  77. presses and releases.
  78.  
  79. The handler is defined in the function 'void far mousehandler(void)'.  This
  80. function is called by the mouse driver upon one of the events happening as
  81. defined in the call to mouse driver function 12.  The handler will
  82. automatically update the mouse cursor, change the global variables mousex
  83. and mousey to the character (not pixel) coordinates of the mouse.  It also
  84. checks for mouse events (button presses and releases) and stores them into
  85. a buffer if an event happens.  This event is later retrieved with a call to
  86. MOUpreview() or MOUget().
  87.  
  88. The drawing of the mouse cursor on non EGA/VGA adapters is quite simple.
  89. It reverses the foreground and background color of the character where the
  90. mouse is located.  This is the default text cursor that the mouse driver
  91. uses itself.
  92.  
  93. On an EGA/VGA adapter, things get a little more complicated.  A 3x3
  94. character arangement is used to draw the cursor.  The function
  95. plotegavgacursor() handles saving the 3x3 character array, restoring it
  96. later, and drawing the 3x3 array of characters that is redefined.  The
  97. redefinition consists of reading the definitions of the characters,
  98. preforming an AND and OR of the mouse cursor onto the existing definitions,
  99. then copying those modified definitions to a new location.  I copy to
  100. characters 0xd0 to 0xd8.  Then the characters 0xd0 to 0xd9 are placed in
  101. the 3x3 grid where the mouse cursor is located, thereby drawing the cursor.
  102.  
  103. The mouse cursor is a simple array of dwords (32 bit unsigned long) that is
  104. used to update the character definitions.  The cursor can be changed from
  105. the default one provided, as defined in the mouse driver documentation for
  106. defining graphics cursors.  It consists of two masks:  the screen mask, and
  107. the cursor mask.  The screen mask is bitwise AND'ed to the existing character
  108. definitions, then the cursor mask is bitwise OR'ed to the existing character
  109. definitions.
  110.  
  111. The functions MOUshow(), MOUhide() and MOUconditionalhide() perform as
  112. their counterpart functions provided by the mouse driver.
  113. MOUconditionalhide() is a special function (that some 'clone' drivers
  114. _don't_ have) that allows you to update a rectangular region on the screen
  115. without distrubing the mouse (if it is not in the region).  It is called
  116. with the character coordinates of a rectangular region on the screen.  If
  117. the mouse is in that region, or if the mouse moves into that region, the
  118. mouse cursor will automatically turn off.  A call to MOUshow() cancels the
  119. rectangular region.  You can't make multiple calls to MOUconditionalhide()
  120. between calls to MOUshow().
  121.  
  122. Various 'glitches' arise by using a 'true' mouse cursor.  They are listed
  123. as follows:
  124.  
  125.   1. On the VGA adapter, standard text mode consists of 9 by 16 characters.
  126.      The character are not actually 9 bits wide, but 8.  The VGA duplicates
  127.      the rightmost bit for the border characters (characters 176 to 218).
  128.      The 'true' cursor uses (rather redefines) characters 208 to 216 (0xd0
  129.      to 0xd8 hex), thereby having its rightmost bit duplicated.  If another
  130.      set of characters is used, the cursor appears to have a 'gap' in the
  131.      middle of it.  The problem lies in that if the cursor is moved over a
  132.      character that has some of its rightmost bit set, the rightmost bit
  133.      will be duplicated.  Characters such as the lower case 'm' are
  134.      examples of this.  It is much easier to see the effect of this than
  135.      explain it.  Run the TEST program that comes with the routines and
  136.      place the cursor over a lower case m on the screen.  You will notice
  137.      the effect.  I can't see any way around this.  This doesn't happen on
  138.      an EGA as the EGA uses 8 pixel width characters (not 9).
  139.  
  140.   2. Since the 'true' mouse cursor is larger than one character, moving the
  141.      cursor into areas of the screen with different foreground colors will
  142.      cause the cursor to take on that color.  If the cursor is at the
  143.      border of two different foreground colors, it will appear that the
  144.      cursor is in two colors.  I got around this by always using the same
  145.      foreground color for all characters on the screen (i.e. WHITE) and
  146.      just using different background colors to show differences on the
  147.      screen.
  148.  
  149.   3. DESQview doesn't like its font changed on the fly.  It interfers with
  150.      the 'true' cursor to the point where it's disfunctional.  The mouse
  151.      routines will automatically detect DESQview and fall back to a normal
  152.      block cursor if running under DV.
  153.  
  154.   4. Since the font is changed, characters 0xd0 to 0xd8 are not available
  155.      for use by the program.  These characters are the IBM border
  156.      characters used to connect double line and single line boxes together.
  157.      I don't use these characters in my programs, and they aren't really
  158.      needed.  If you need to have a single line join a double line graphics
  159.      character, just place them side by side.  They won't actually 'join'
  160.      as it would by using a double to single line character, but they will
  161.      line up closely.  I find it an acceptable loss to provide a 'true'
  162.      mouse cursor on the EGA/VGA.
  163.  
  164. For a description of how to change fonts on the EGA/VGA adapters, I highly
  165. recommend the book by Richard Wilton, _Programmer's Guide to PC & PS/2
  166. Video Systems_.  An excellant book if you are doing any kind of video
  167. programming.  For a description of the mouse driver interface, I can
  168. recommend Logitech's Mouse Programmer's Toolkit, Microsoft Press's Mouse
  169. Reference Guide, and Ralf Brown's Interrupt List (updated periodically).
  170. I initially learned the interface to the mouse driver from an article in PC
  171. Magazine (I can't remember what issue), and I use Ralf Brown's Interrupt
  172. List for reference now.
  173.  
  174. 3. Variable and definition reference.
  175. -------------------------------------
  176.  
  177. The following variables and defintions are included in MOU.H:
  178.  
  179. MOUINFOREC              This is the definition for the structure returned
  180.                         by the functions MOUpreview() and MOUget().  It
  181.                         contains the following fields:
  182.                           word buttonstat:  bits in this field indicate
  183.                             what event occured.  See them below.
  184.                           int cx, cy: character coordinates of where this
  185.                             event occured.
  186.                           byte shiftshate:  the status of the shift keys at
  187.                             the time of the event.  See definitions below.
  188.  
  189. MOUSEBUFFERSIZE         This is the size of the mouse buffer.  The buffer
  190.                         is where mouse events are held for the program
  191.                         until is retrieves them with MOUget().
  192.  
  193. MOUSEMOVE,              These defines are for the field buttonstat in the
  194.   LEFTBPRESS            MOUINFOREC structure.  By checking the bits of
  195.   LEFTBRELEASE,         buttonstat, you can find out what event occured,
  196.   RIGHTBPRESS,          for example, "if (m.buttonstat & LEFTBPRESS)" will
  197.   RIGHTBRELEASE         be true if the event was caused by the press of the
  198.                         left mouse button.
  199.  
  200. LEFTBDOWN,              These defines are used for the value returned by
  201.   RIGHTBDOWN            the function MOUbuttonstatus().  I.e.
  202.                         "if (MOUbuttonstatus() & LEFTBDOWN)" will be TRUE
  203.                         if the left mouse button is currently down.
  204.  
  205. SHIFT_RIGHTSHIFT,       These defines are for the shiftstate field in the
  206.   SHIFT_LEFTSHIFT,      MOUINFOREC structure.  It allows you to check for
  207.   SHIFT_SHIFT,          such things as shift-clicks.  I.e.
  208.   SHIFT_CTRL,           "if (m.shiftstate & SHIFT_LEFTSHIFT)" will be TRUE
  209.   SHIFT_ALT,            if the left shift key was held down during the
  210.   SHIFT_SCROLLLOCK,     mouse event.  SHIFT_SHIFT is defined as both
  211.   SHIFT_NUMLOCK,        shift keys.
  212.   SHIFT_CAPSLOCK,
  213.   SHIFT_INS
  214.  
  215. word mousehidden        This variable will be true (non-zero) if the mouse
  216.                         is currently hidden.  It is undefined if
  217.                         mouseinstalled is false.  Don't write to this
  218.                         variable, it's just provided for your reference.
  219.  
  220. boolean mouseinstalled  This variable will be true (non-zero) if a mouse
  221.                         driver is installed and operating and the mouse
  222.                         routines are active and reading the mouse and
  223.                         drawing the cursor.  If it is false, the mouse
  224.                         driver routines will not operate, calling them will
  225.                         do nothing (but calling them is not harmful).
  226.  
  227. volatile int mousex,    These variables hold the current location of the
  228.   mousey                mouse cursor.  They are updated by the mouse
  229.                         handler.  Note that their value may changed at
  230.                         _any_ time.  Don't depend on them being constant.
  231.                         If you need to reference them, I recommend
  232.                         declaring a couple of variables to hold their
  233.                         values (i.e. int x, y;  x = mousex; y = mousey;)
  234.                         and using those instead of mousex and mousey.  Only
  235.                         reference mousex and mousey when you need to update
  236.                         the position.
  237.  
  238.  
  239. 4. Function reference.
  240. ----------------------
  241.  
  242. /* Initialize the mouse routines -- must be called. */
  243. void    FAST MOUinit(void);
  244.  
  245.   This function initializes the mouse routines, checks for presense of the
  246.   mouse driver, DESQview and an EGA/VGA.  What it does is described above
  247.   in "How does it work?".
  248.  
  249. /* Deinitialize the mouse routines -- must be called on shutdown.
  250.    Failure to call it will most likely result in a system crash if the mouse
  251.    is moved. */
  252. void    FAST MOUdeinit(void);
  253.  
  254.   This function will deinitialize the mouse routines.  It will stop the
  255.   mouse driver from calling the handler, and erase the mouse cursor.  You
  256.   can call MOUinit() if you wish to use the mouse driver routines again.
  257.   You MUST call this function before you quit your program.  Failure to do
  258.   so will most likely cause your computer to crash next time the mouse is
  259.   moved.  If you don't call it, the mouse driver still calls the mouse
  260.   hander, even after the program has quit.
  261.  
  262. /* Hide the mouse cursor */
  263. void    FAST MOUhide(void);
  264.  
  265.   This hides the mouse cursor.  The mouse cursor must be hidden with this
  266.   function (or MOUconditionalhide() below) before doing any screen
  267.   updating.  This prevents overwritting the mouse cursor.  The prefered way
  268.   to hide the mouse is MOUconditionalhide().  But if you are clearing the
  269.   screen, or updating all of it at once, use this function.  This function
  270.   counts how many times it has been called, i.e. if you call it twice, you
  271.   have to call MOUshow() twice to get the cursor back on the screen.
  272.  
  273. /* Hide the mouse cursor if it moves or is in a specific rectangular region
  274.    of the screen. */
  275. void    FAST MOUconditionalhide(int x1, int y1, int x2, int y2);
  276.  
  277.   This function hides the mouse automatically if it is in, or is moved in,
  278.   the retangular region defined by this function.  If possible use this
  279.   function to hide the mouse, as if the mouse isn't near the area being
  280.   updated, it won't 'blink' like it would calling MOUhide().  The
  281.   coordinates are zero based and x1 must be <= x2 and y1 must be <= y2.
  282.   Call MOUshow() after you want the cursor to reappear (if it was hidden by
  283.   this function).
  284.  
  285. /* Show the mouse cursor */
  286. void    FAST MOUshow(void);
  287.  
  288.   This turns on the mouse cursor after a previous call to MOUhide() or
  289.   MOUconditionalhide().  This function may be called as many times as you
  290.   like, once the cursor is not hidden, any other calls will have no effect.
  291.  
  292. /* return TRUE if there are events waiting in the buffer. */
  293. boolean FAST MOUcheck(void);
  294.  
  295.   This function returns true (non-zero) if there are events in the buffer,
  296.   if not it returns false (zero).
  297.  
  298. /* look at the next event in the buffer, but don't pull it out. */
  299. void    FAST MOUpreview(MOUINFOREC *mouinforec);
  300.  
  301.   This function passes the next event to the MOUINFOREC passed to it.  It
  302.   does not remove the event from the buffer.  If there are no events in the
  303.   buffer, the MOUINFOREC returned will have the current mouse position in
  304.   the cx and cy fields of the MOUINFOREC, the shiftstate field set to the
  305.   current state of the shift keys, and the buttonstat field blank (zero, or
  306.   no events).
  307.  
  308. /* get and remove next event from the buffer. */
  309. void    FAST MOUget(MOUINFOREC *mouinforec);
  310.  
  311.   This function passes the next event to the MOUINFOREC passed to it.  It
  312.   will remove the event from the buffer.  If there are no events in the
  313.   buffer, the MOUINFOREC returned will have the current mouse position in
  314.   the cx and cy fields of the MOUINFOREC, the shiftstate field set to the
  315.   current state of the shift keys, and the buttonstat field blank (zero, or
  316.   no events).
  317.  
  318. /* return the current status of the mouse buttons (see defines above). */
  319. word    FAST MOUbuttonstatus(void);
  320.  
  321.   This will return the current status of the mouse buttons.  It can be
  322.   ANDed with LEFTBDOWN and RIGHTBDOWN to see if either button is currently
  323.   being held down.  This function could be used to detect dragging of the
  324.   mouse.
  325.  
  326. 5. The test program.
  327. --------------------
  328.  
  329. Included with the routines is a small test program that will allow you to
  330. see the 'true' mouse cursor (if you have an EGA/VGA adapter).  Included is
  331. a makefile for NDMake and Turbo C.  If you don't have a makefile, you can
  332. compile it like this:
  333.  
  334.   tcc -ml test.c mou.c
  335.  
  336. or under MSC as:
  337.  
  338.   cl /AL test.c mou.c
  339.  
  340. Note: with Turbo C, you will require to have TASM in your path as the
  341. routines have inline assembler in them.  MASM isn't required for MSC (MSC
  342. has a built in assembler, though it's a bit dumb at times).
  343.  
  344. It's a simple program that will tell you the current mouse position and the
  345. status of the mouse buttons.
  346.  
  347. The mouse routines will work in ALL EGA/VGA text modes.  I've run it in
  348. 80x25 and 80x50 mode and the 'true' cursor will be drawn in both those
  349. modes.  My VGA supports a 132x60 mode as well, and the 'true' mouse cursor
  350. works prefectly in that mode as well.
  351.  
  352. The test program requires ANSI.SYS to be installed.
  353.  
  354.  
  355. 6. Disclaimer and other stuff.
  356. ------------------------------
  357.  
  358. I orginally started working on these routines when I first saw the new
  359. version of Norton's Utilities (version 5.0).  I was impressed with the
  360. 'true' mouse cursor it was drawing in text mode, and wanted to know if I
  361. could write a set of routines to do the same thing.
  362.  
  363. In Jan. of '91, a discussion on the group comp.os.msdos.program about the
  364. way Norton does the 'true' mouse cursor arose.  I replied to a message by
  365. Brian K. W. Hook who indicated that he doubted Norton changed the font on
  366. the fly the implement a 'true' mouse cursor in text mode.  He stated he was
  367. 'baffled' by the way that Norton did it.  I stated that Norton did do it by
  368. changing the font on the fly, and that I had written some routines to do it
  369. as well.
  370.  
  371. Brian asked me for the routines, as well as a couple of other users, so I
  372. cleaned them up, made them independant of my text window library (I've
  373. written a library for text window routines that I use in my programs) and
  374. otherwise prepared to unleash them on unsuspecting Usenet victims. :)
  375.  
  376. These routines also illustrate interfacing to mouse driver function 12,
  377. which seems to be a common question on comp.os.msdos.program (How to I do
  378. interface to the mouse driver?).
  379.  
  380. I'll supply support for these routines as my time permits, and I can be
  381. reached by any of the following methods of communication:
  382.  
  383. Email:  UUCP:            {uunet,ubc-cs}!van-bc!rsoft!mindlink!a563
  384.         Usenet:          a563@mindlink.UUCP
  385.                          zoid@threewave.wimsey.bc.ca
  386.         Internet/Bitnet: Zoid@cc.sfu.ca
  387.  
  388.         a563@mindlink.UUCP is prefered, Zoid@cc.sfu.ca would be the next
  389.         one to try.
  390.  
  391. Mail:   #801-9835 King George Hwy.
  392.         Surrey, BC  Canada
  393.         V3T 5H6
  394.  
  395. Phone:  604-585-8844 or 604-439-7770
  396.  
  397. I do hope you enjoy these routines, and have an 'edge' on the competition
  398. by having a flashy 'true' cursor on the EGA/VGA.  Wow!
  399.  
  400.  
  401.  
  402.                                 DISCLAIMER
  403.  
  404.    Dave Kirsch makes no warranty of any kind, either express or implied,
  405.    including but not limited to implied warranties of merchantability
  406.    and fitness for a particular purpose, with respect to this software
  407.    and accompanying documentation.
  408.  
  409.    IN NO EVENT SHALL DAVE KIRSCH BE LIABLE FOR ANY DAMAGES (INCLUDING
  410.    DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF
  411.    BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OUT OF THE
  412.    USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF DAVE KIRSCH HAS BEEN
  413.    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  414.  
  415.    Programmers may incorporate any or all code into their programs,
  416.    giving proper credit within the source. Publication of the
  417.    source routines is permitted so long as proper credit is given
  418.    to Dave Kirsch.
  419.  
  420.                  Copyright (C) 1990, 1991 by Dave Kirsch.
  421.  
  422.